Ext.ns("org.cancerregulome.molotov.js");

org.cancerregulome.molotov.js.Viewport = Ext.extend(Ext.util.Observable, {
    constructor: function(config) {
        Ext.apply(this, config);

        org.cancerregulome.molotov.js.Viewport.superclass.constructor.call(this);

        this.loading = new org.cancerregulome.molotov.js.LoadingMessage();

        this.addEvents("fetch-query");
        this.on("fetch-query", function(numberOfTimes) {
            if (numberOfTimes === undefined) {
                numberOfTimes = 1;
            }

            this.resultsPanel.removeAll(true);
            this.resultsPanel.add({ html: "Loading..." });
            this.resultsPanel.doLayout();

            this.loading.start();
            this.loadQuery.defer(1000, this, [numberOfTimes]);
        }, this);

        this.loadViewport();
        this.expandNode(this.rootNode);
        this.loadPastQueries();
        this.selectTable(this.history.tableId);

        if (this.history.queryUri) {
            this.fireEvent("fetch-query");
        }
    },

    loadViewport: function() {
        var toolbarPanel = this.newToolbar();
        var queriesTabPanel = this.newQueriesTabPanel();
        var resultsTabPanel = this.newResultsTabPanel();
        var datasetsPanel = this.newTreePanel();
        var pqPanel = this.newPastQueriesPanel();
        var footerPanel = this.newFooterPanel();

        new Ext.Viewport({
            layout: "border",
            items:[
                toolbarPanel, datasetsPanel, pqPanel, footerPanel,
                new Ext.Panel({
                    layout: "border", region: "center", border: false, items:[ queriesTabPanel, resultsTabPanel ]
                })
            ]
        });
    },

    newToolbar: function() {
        this.homeBtn = new Ext.Button({
            text: "BigQuery Motif Locator Results",
            handler: function() {
                document.location = "/";
            }
        });
        
        this.refreshUIBtn = new Ext.Button({
            text: "Refresh UI Version",
            handler: function() {
                Ext.Ajax.request({
                    method: "POST",
                    url: "/html/refresh",
                    success: function() {
                        document.location = document.location.href;
                    }
                });
            }
        });

        return new Ext.Toolbar({ region: "north", height: 30, items: [ this.homeBtn, '-', this.refreshUIBtn ] });
    },

    newQueriesTabPanel: function() {
        this.pwmField = new Ext.form.TextField({ name: "pwmField", fieldLabel: "PWM Name", labelSeparator: "", emptyText: "e.g. FOXO3" });
        this.chrmField = new Ext.form.TextField({ name: "chrmField", fieldLabel: "Chromosome", labelSeparator: "", emptyText: "e.g. chr11" });
        this.startField = new Ext.form.NumberField({ name: "startField", fieldLabel: "Start Location", labelSeparator: "  >=", allowDecimals: false });
        this.endField = new Ext.form.NumberField({ name: "endField", fieldLabel: "End Location", labelSeparator: "  <=", allowDecimals: false });
        this.pvalueField = new Ext.form.NumberField({ name: "pvalueField", fieldLabel: "p-value", labelSeparator: "  <", decimalPrecision: 20 });
        this.pvalueField2 = new Ext.form.NumberField({ name: "pvalueField2", fieldLabel: "p-value", labelSeparator: "  <", decimalPrecision: 20 });

        return new Ext.TabPanel({
            region: "north",
            collapsible: true,
            defaults: {
                padding: "5 5 5 5",
                height: 160,
                buttonAlign: "left"
            },
            activeTab: 0,
            items: [
                {
                    title: "Query By PWM",
                    layout: "form",
                    frame: true,
                    items: [this.pwmField, this.pvalueField],
                    buttons: [ new Ext.Button({ text: "Query", handler: this.queryPwm, scope: this }) ]
                },
                {
                    title: "Query By Chromosome",
                    layout: "form",
                    frame: true,
                    items: [this.chrmField, this.startField, this.endField, this.pvalueField2],
                    buttons: [ new Ext.Button({ text: "Query", handler: this.queryChrm, scope: this }) ]
                }
            ]
        });
    },

    newResultsTabPanel: function() {
        var ajaxMonitor = new org.systemsbiology.addama.js.widgets.AjaxMonitor();

        this.resultsPanel = new Ext.Panel({
            title: "Results",
            layout: "fit",
            frame: true,
            border: true
        });

        return new Ext.TabPanel({
            region: "center",
            collapsible: true,
            defaults: {
                padding: "5 5 5 5",
                height: 120
            },
            activeTab: 0,
            items: [
                this.resultsPanel, ajaxMonitor.gridPanel
            ]
        });
    },

    newTreePanel: function() {
        this.rootNode = new Ext.tree.AsyncTreeNode({
            id: "/datasets"
        });

        this.treePanel = new Ext.tree.TreePanel({
            title: "Datasets",
            region:"west",
            split: true,
            autoScroll: true,
            border: true,
            width: 275,
            frame: true,
            collapsible: true,
            // tree-specific configs:
            rootVisible: false,
            lines: false,
            singleExpand: true,
            useArrows: true,
            loader: new Ext.tree.TreeLoader(),
            root: this.rootNode
        });
        this.treePanel.on("expandnode", this.expandNode, this);
        this.treePanel.on("expandnode", this.selectNode, this);
        this.treePanel.on("click", this.selectNode, this);
        return this.treePanel;
    },

    newPastQueriesPanel: function() {
        this.pastQueriesStore = new Ext.data.ArrayStore({
            fields: [ "id", "uri", "status", {name:"startTimeFromEpoch", type:"int"}, "errorMsg", "tq", "tableId", "payload"],
            sortInfo: { field: "startTimeFromEpoch", direction: "DESC" }
        });

        this.listView = new Ext.list.ListView({
            store: this.pastQueriesStore,
            deferEmptyText: false,
            emptyText: "No past queries found",
            hideHeaders: true,
            singleSelect: true,
            columns: [
                { tpl: "<ul><li>{id}</li><li>{status}</li><li>{payload}</li><li>{errorMsg}</li></ul><hr/>" }
            ]
        });
        this.listView.on("click", this.loadPastQuery, this);

        return new Ext.Panel({
            title: "Past Queries",
            region: "east",
            width: 275,
            collapsible: true,
            collapsed: true,
            layout: "fit",
            frame: true,
            border: true,
            items: [this.listView]
        });
    },

    newFooterPanel: function() {
        var link1 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://cancergenome.nih.gov" target="_blank">TCGA</a></div>', true);
        var link2 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://cancerregulome.org" target="_blank">Cancer Regulome Project</a></div>', true);
        var link3 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://www.systemsbiology.org" target="_blank">Institute for Systems Biology</a></div>', true);
        var link4 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://shmulevich.systemsbiology.net/" target="_blank">Shmulevich Lab</a></div>', true);
        var link5 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://codefor.systemsbiology.net/" target="_blank">Code for Systems Biology</a></div>', true);
        var link6 = Ext.DomHelper.append(Ext.getBody(), '<div><a href="http://cancerregulome.googlecode.com" target="_blank">Source Code</a></div>', true);

        return new Ext.Panel({
            region:"south",
            height: 33,
            layout: "hbox",
            border: false,
            frame: true,
            padding: "1 1 1 1",
            margins: "1 1 1 1",
            layoutConfig: { pack: "center", align: "middle", defaultMargins: "0 10 0 0" },
            items:[ link1.dom, link2.dom, link3.dom, link4.dom, link5.dom, link6.dom ]
        });
    },
    
    loadPastQuery: function(view, index, node) {
        var record = this.listView.getRecord(node);
        this.history.setQueryUri(record.data.uri);
        this.fireEvent("fetch-query");
    },

    loadPastQueries: function() {
        Ext.Ajax.request({
            method: "GET",
            url: "/queries",
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json && json.items) {
                    var data = [];
                    Ext.each(json.items, function(item) {
                        data.push([item.id, item.uri, item.status, item.startTimeFromEpoch, item.errorMsg, item.tq, item.tableId, item.payload]);
                    });
                    this.pastQueriesStore.loadData(data);
                }
            },
            scope: this
        });
    },

    expandNode: function(node) {
        Ext.Ajax.request({
            url: node.id,
            method: "GET",
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json && json.items) {
                    this.addNodes(node, json.items);
                }
            },
            scope: this,
            failure: function(o) {
                org.systemsbiology.addama.js.Message.error("Datasets", "Error Loading: " + o.statusText);
            }
        });
    },

    addNodes: function(node, items) {
        Ext.each(items, function(item) {
            item.id = item.uri;

            if (!this.treePanel.getNodeById(item.id)) {
                item.text = item.label ? item.label : item.name;
                item.path = item.id;
                if (item.tableId) {
                    item.leaf = true;
                    item.cls = "file";
                } else {
                    item.cls = "folder";
                    item.children = [];
                }
                node.appendChild(item);
            }
        }, this);
    },

    selectNode: function(node) {
        if (node && node.attributes) {
            this.selectTable(node.attributes.tableId);
        }
    },

    selectTable: function(tableId) {
        if (tableId) {
            this.history.setTableId(tableId);
            org.systemsbiology.addama.js.Message.show("Datasets", "Table Selected: " + tableId);
        }
    },

    queryPwm: function() {
        var pwm = this.pwmField.getRawValue();
        var pvalue = this.pvalueField.getRawValue();
        var tId = this.history.tableId;

        var payload = pwm;
        var tq = "SELECT CHROMOSOME, START_POS, END_POS, STRAND, MOTIF_CHARACTER_PROB, NORMALIZED_SCORE, AGGREGATE_SCORE, PWM_NAME, SEQUENCE, P_VALUE FROM " + tId + " WHERE PWM_NAME = '" + pwm + "';";
        if (pvalue != null && pvalue.length) {
            payload += "," + pvalue;
            tq = "SELECT CHROMOSOME, START_POS, END_POS, STRAND, MOTIF_CHARACTER_PROB, NORMALIZED_SCORE, AGGREGATE_SCORE, PWM_NAME, SEQUENCE, P_VALUE FROM " + tId + " WHERE PWM_NAME = '" + pwm + "' AND P_VALUE < " + pvalue + ";";
        }
        this.sendQuery({ tq: tq, tableId: tId, payload: "[" + payload + "]" });
    },

    queryChrm: function() {
        var chr = this.chrmField.getRawValue();
        var start = this.startField.getRawValue();
        var end = this.endField.getRawValue();
        var pvalue = this.pvalueField2.getRawValue();
        var tId = this.history.tableId;

        var payload = chr + "," + start + "," + end;
        var tq = "SELECT CHROMOSOME, START_POS, END_POS, STRAND, MOTIF_CHARACTER_PROB, NORMALIZED_SCORE, AGGREGATE_SCORE, PWM_NAME, SEQUENCE, P_VALUE FROM " + tId + " WHERE CHROMOSOME=\"" + chr + "\" AND START_POS>=" + start + " AND END_POS<=" + end + ";";
        if (pvalue != null && pvalue.length) {
            payload += "," + pvalue;
            tq = "SELECT CHROMOSOME, START_POS, END_POS, STRAND, MOTIF_CHARACTER_PROB, NORMALIZED_SCORE, AGGREGATE_SCORE, PWM_NAME, SEQUENCE, P_VALUE FROM " + tId + " WHERE CHROMOSOME=\"" + chr + "\" AND START_POS>=" + start + " AND END_POS<=" + end + " AND P_VALUE < " + pvalue + ";";
        }
        this.sendQuery({ tq: tq, tableId: tId, payload: "[" + payload + "]" });
    },

    sendQuery: function(params) {
        if (!this.history.tableId) {
            org.systemsbiology.addama.js.Message.show("Queries", "Please select table before proceeding");
            return;
        }

        Ext.Ajax.request({
            method: "POST",
            url: "/queries",
            params: params,
            success: function(o) {
                var json = Ext.util.JSON.decode(o.responseText);
                if (json) {
                    this.history.setQueryUri(json.uri);
                    this.fireEvent("fetch-query");
                }
            },
            failure: function(o) {
                org.systemsbiology.addama.js.Message.error("Queries", "Error: " + o.statusText);
            },
            scope: this
        });
    },

    loadQuery: function(numberOfTimes) {
        if (numberOfTimes > 5) {
            this.loading.done();
            org.systemsbiology.addama.js.Message.error("Queries", "Exceeded number of tries.  Refresh page to try again later");
            return;
        }

        var uri = this.history.queryUri;
        if (uri) {
            Ext.Ajax.request({
                method: "GET",
                url: uri,
                success: function(o) {
                    var results = Ext.util.JSON.decode(o.responseText);
                    if (results && results.data && results.dataSchema) {
                        this.loadDataGrid(results.data, results.dataSchema);
                        this.loading.done();
                    } else {
                        this.fireEvent("fetch-query", numberOfTimes++);
                    }
                },
                failure: function(o) {
                    org.systemsbiology.addama.js.Message.error("Queries", "Error: " + o.statusText);

                    this.resultsPanel.removeAll(true);
                    this.resultsPanel.add({ html: o.responseText });
                    this.resultsPanel.doLayout();
                },
                scope: this
            });
        }
    },

    loadDataGrid: function(data, columns) {
        if (data && columns && data.length && columns.length) {
            org.systemsbiology.addama.js.Message.show("Data", "Retrieved " + data.length + " Records");

            var fields = new Array();
            Ext.each(columns, function(column) {
                fields.push(column.name);
                column.id = column.name;
                column.header = column.name;
                column.dataIndex = column.name;
            });

            var store = new Ext.data.JsonStore({ autoDestroy: true, root : 'results', fields: fields });
            store.loadData({ results: data });

            var tableId = this.history.tableId;
            if (tableId) {
                this.resultsPanel.setTitle("Results from query on " + tableId);
            }

            var grid = new Ext.grid.GridPanel({
                store: store,
                colModel: new Ext.grid.ColumnModel({ defaults: { width: 200, sortable: true }, columns: columns }),
                stripeRows: true,
                iconCls: 'icon-grid'
            });

            this.resultsPanel.removeAll(true);
            this.resultsPanel.add(grid);
            this.resultsPanel.doLayout();
        } else {
            org.systemsbiology.addama.js.Message.error("Datasets", "No Data Loaded");
        }
    }

});

org.cancerregulome.molotov.js.LoadingMessage = Ext.extend(org.systemsbiology.addama.js.widgets.MessageHelper, {
    constructor: function(config) {
        Ext.apply(this, config);

        org.cancerregulome.molotov.js.LoadingMessage.superclass.constructor.call(this);
    },

    start: function() {
        if (!this.loadingEl) {
            var msgBox = '<div class="msg"><h3>Loading</h3><p>Please wait...</p></div>';
            this.loadingEl = Ext.DomHelper.append(this.messageContainer, msgBox, true);
            this.loadingEl.hide();
            this.loadingEl.slideIn('t', { duration:1 });
        }
    },

    done: function() {
        this.loadingEl.puff('t', { duration:1 }).ghost('t', {duration:1, remove:true});
        this.loadingEl = null;
    }

});